<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WeakSet</title>
</head>
<body>
  <script>
    var z = 1;
    /**
     * WeakSet结构与Set类似，也是不能重复的值的集合，但是，它与Set有俩个区别。
     * 首先，WeakSet的成员只能是对象，而不能是其他类型的值。
    */
  //  var ws = new WeakSet();
  //  ws.add(1);
  //  // TypeError: Invalid value used in weak set
  //  ws.add(Symbol())
  //  // TypeError: invalid value used in weak set
   /**
    * 上面代码试图向WeakSet添加一个数值和Symbol值，结果报错，因为WeakSet只能放置对象
    * 其次，weakset中的对象都是弱引用，即垃圾回收机制不考虑weakset对该对象的引用，
    * 也就是说，如果其他对象都不再引用该对象，那么垃圾回收机制，会自动回收该对象所占的内存，不考虑该对象还存在于weakset中。
    * 这是因为垃圾回收机制根据对象的可达性(reachability)来判断回收，如果对象还能被访问到。垃圾回收机制就不会释放这块内存。
    * 结束使用该值之后，有时会忘记取消引用，导致内存无法释放，进而可能会引发内存泄漏，weakset里面的引用，都不计入垃圾回收机制，所以就不存在这个问题
    * 因此，weakset适合临时存放一组对象，以及存放跟对象绑定的信息，只要这些对象在外部消失，它在weakset里面的引用就会自动消失。
    * 由于上面这个特点，WeakSet 的成员是不适合引用的，因为它会随时消失。另外，由于 WeakSet 内部有多少个成员，取决于垃圾回收机制有没有运行，
    * 运行前后很可能成员个数是不一样的，而垃圾回收机制何时运行是不可预测的，因此 ES6 规定 WeakSet 不可遍历。
   */
  // WeakSet是一个构造函数，可以使用new 命令，创建WeakSet数据结构
  var ws = new WeakSet();
  /**
   * 作为构造函数，weakset可以接受一个数组或者类似数组的对象作为参数，实际上，任何具有iterable接口的对象，都可以作为WeakSet的参数
   * 该数组的所有成员，都会自动成为Weakset实例对象的成员。
  */
 var a = [[1,2], [3,4]];
 var ws = new WeakSet(a);
 console.log(ws) // // WeakSet {[1, 2], [3, 4]}
 /**
  * WeakSet结构有以下三个方法。
  * WeakSet.prototype.add(value)：向 WeakSet 实例添加一个新成员。
  * WeakSet.prototype.delete(value)：清除 WeakSet 实例的指定成员。
  * WeakSet.prototype.has(value)：返回一个布尔值，表示某个值是否在 WeakSet 实例之中。
 */
var ws = new WeakSet();
var obj = {};
var foo = {};
ws.add(window);
ws.add(obj);
ws.has(window); // true
ws.has(foo); // false
ws.delete(window);
ws.has(window); // false
// WeakSet没有size属性，没有办法遍历它的成员
// WeakSet 不能遍历，是因为成员都是弱引用，随时可能消失，遍历机制无法保证成员的存在，
// 很可能刚刚遍历结束，成员就取不到了。WeakSet 的一个用处，是储存 DOM 节点，而不用担心这些节点从文档移除时，会引发内存泄漏。

var foos = new WeakSet();
class Foo {
  constructor() {
    foos.add(this)
  }
  method() {
    if (!foos.has(this)) {
      throw new TypeError('Foo.prototype.method 只能在Foo实例上调用!')
    }
  }
}
/**
 * 上面代码保证了Foo的实例方法，只能在Foo的实例上调用，，这里使用WeakSet的好处是，
 * foos对实例的引用，不会被计入内存回收机制，所以删除实例的时候，不用考虑foos，也不会出现内存泄漏
*/
</script>
</body>
</html>